﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BldcControl
{
    public partial class Form1 : Form
    {
        Queue<byte> queue = new Queue<byte>();
        const int CMD_PWM = 1;
        const int CMD_STATE = 2;
        int recv_cnt=0;

        const int LINE_SIZE = 100;
        int[] current = new int[LINE_SIZE];
        int[] speed = new int[LINE_SIZE];

        int max_current = 0;
        int over_current=0;
        int over_load = 0;

        public Form1()
        {
            InitializeComponent();

            labelPWM.Text = trackBarPWM.Value.ToString();

            draw_rec();

            for(int i=0;i<LINE_SIZE;i++)
            {
                current[i] = Math.Abs((int)(Math.Sin((i+90)%360) * 10000));
            }
        }

        private void trackBarPWM_Scroll(object sender, EventArgs e)
        {
            labelPWM.Text = trackBarPWM.Value.ToString();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            serial_send_pwm();
            textBox1.Text = "recv_cnt = " + recv_cnt.ToString();

            draw_line();

            labelMaxCurrent.Text =  "Max Current:" + max_current.ToString();
            labelCurrent.Text =     "Current    :" + current[LINE_SIZE - 1].ToString();
            labelOverCurrent.Text = "OverCurrent:" + over_current.ToString();
            labelOverLoad.Text =    "OverLoad:" + over_load.ToString();
            labelSpeed.Text = "Speed:" + speed[LINE_SIZE - 1].ToString();
        }

        private void draw_line()
        {
            Bitmap bitmap = new Bitmap(800, 400);

            Pen pen = new Pen(Color.Red, 1);//灰色画笔，宽度为1
            Graphics g = Graphics.FromImage(bitmap);        

            g.DrawRectangle(pen, 0, 0, 800, 400);

            for (int i = 0; i < LINE_SIZE-1; i++)
            {
                g.DrawLine(pen, 8*i, 200 - ((current[i]%10000) / 30), 8*(i + 1), 200 - ((current[i+1] % 10000) / 30));

                g.DrawLine(new Pen(Color.Green, 1), 8 * i, 300 - ((speed[i] % 10000) / 30), 8 * (i + 1), 300 - ((speed[i + 1] % 10000) / 30));
            }

            pictureBox1.Image = bitmap;
        }

        private void draw_rec()
        {

        }

        private void comboBox1_Click(object sender, EventArgs e)
        {
            comboBox1.Items.Clear();

            string[] portNames = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(portNames);
        }

        private void buttonCom_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
                buttonCom.Text = "连接";
            }
            else
            {
                try
                {
                    serialPort1.BaudRate = 9600;
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.Open();
                    Thread thread = new Thread(serial_recv_thread);
                    thread.Start();
                }
                catch
                {

                }

                if(serialPort1.IsOpen)
                {
                    buttonCom.Text = "断开";
                }
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                int n = serialPort1.BytesToRead;
                for(int i = 0; i<n;i++)
                {               
                    queue.Enqueue((byte)serialPort1.ReadByte());                
                }
            }
            catch
            {

            }
        }

        private byte calc_bcc(byte[] buf, int len)
        {
            byte bcc = 0;
            for(int i=0;i<len;i++)
            {
                bcc ^= buf[i];
            }

            return bcc;
        }

        private void serial_send_pwm()
        {
            if (serialPort1.IsOpen)
            {
                byte[] array = new byte[6];

                array[0] = 0x02;
                array[1] = 6;
                array[2] = CMD_PWM;
                array[3] = (byte)(checkBoxPWM.Checked ? 1 : 0);
                array[4] = (byte)trackBarPWM.Value;
                array[5] = calc_bcc(array,5);

                serialPort1.Write(array, 0, 6);
            }
        }

        private void serial_recv_thread()
        {
            int rx_state = 0;
            byte[] rx_buf = new byte[100];
            int rx_count = 0;
            byte bcc = 0;
            int uart_package_len = 0;

            while (serialPort1.IsOpen)
            {
                if (queue.Count > 0)
                {
                    while (queue.Count > 0)
                    {
                        byte data = queue.Dequeue();
                        recv_cnt++;
                    
                        switch (rx_state)
                        {
                            case 0: //recv STX
                                if (data == 0x02)
                                {
                                    rx_state = 1;
                                    rx_buf[0] = data;
                                    rx_count = 1;
                                }
                                break;
                            case 1: //recv len
                                uart_package_len = data;
                                if (uart_package_len < 4 || uart_package_len > rx_buf.Length) //package len error
                                {
                                    rx_state = 0;
                                    rx_count = 0;
                                    break;
                                }

                                rx_buf[rx_count] = data;
                                rx_count++;
                                rx_state = 2;
                                break;
                            case 2: //recv data
                                rx_buf[rx_count] = data;
                                rx_count++;

                                if (rx_count == uart_package_len)
                                {
                                    bcc = calc_bcc(rx_buf, uart_package_len - 1);
                                    if (bcc == rx_buf[uart_package_len - 1])
                                    {
                                        /* recv packet success */
                                        uart_package_parse(rx_buf);
                                    }

                                    rx_state = 0;
                                    rx_count = 0;
                                }
                                break;
                        }
                    }
                }
            }
        }

        void uart_package_parse(byte[] buf)
        {
            byte cmd = buf[2];
            switch (cmd)
            {
                case CMD_STATE:
                    for(int i=0;i< (LINE_SIZE-1); i++)
                    {
                        current[i] = current[i + 1];
                        speed[i] = speed[i + 1];
                    }

                    current[LINE_SIZE - 1] = buf[5] << 8 | buf[6];
                    speed[LINE_SIZE - 1] = buf[7] << 8 | buf[8];
                    over_current = buf[9];
                    over_load = buf[10];

                    max_current = 0;
                    for(int i=0;i<current.Length;i++)
                    {
                        if(current[i]>max_current)
                        {
                            max_current = current[i];
                        }
                    }
                    break;
            }
        }
    }
}
